import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:archive/archive_io.dart';

class LogManager {
  /// 日志文件的文件夹
  final documentName = "logs";
  LogManager._internal();
  static LogManager get instance => _instance;
  factory LogManager() => _instance;
  static late final LogManager _instance = LogManager._internal();
  bool _willClearLogs = false;
  bool _logging = false;
  String _cacheLogs = "";
  String _cacheLevel01 = "";

  Future<void> sdkInit() async {
    final logs = await getLogs();
    for(final log in logs) {
      final filename = log.filename;
      final dateArr = filename.split('-').map(int.parse).toList();
      final createDate = DateTime(dateArr[0],dateArr[1], dateArr[2]);
      final currentDate = DateTime.now();
      var diff = currentDate.difference(createDate).inDays;
      if (diff < 0) diff = (diff - 1).abs();
      if (diff >= 7) await log.delete(recursive: true);
    }
  }

  /// 将[message]写入当天创建的日志文件中
  Future<LogManager> writeLog(String message) async {
    if (_willClearLogs) {
      _cacheLogs += "$message\n";
      return this;
    }
    String tempMessage = "";
    if (_cacheLogs.isNotEmpty) {
      tempMessage = "$_cacheLogs\n";
      _cacheLogs = "";
    }
    tempMessage += message;
    final fpath = await filepath(filename());
    await localLog(tempMessage, fpath);
    return this;
  }
  writeLogSync(String message) async {
    if (_logging || _willClearLogs) {
      _cacheLevel01 += "$message\n";
      return this;
    }
    _logging = true;
    String tempMessage = "";
    if (_cacheLevel01.isNotEmpty) {
      tempMessage = "$_cacheLevel01\n";
      _cacheLevel01 = "";
    }
    tempMessage += message;
    final fpath = await filepath(filename());
    await localLog(tempMessage, fpath);
    _logging = false;
    return this;
  }
  /// 获取[filePath]路径下的日志文件内容
  Future<String> readLogAsync(String filePath) async {
    try {
      final file = await localFile(filePath);
      return await file.readAsString();
    } catch(e) {
      rethrow;
    }
  }

  /// 删除指定[filePath]的日志文件
  /// 返回删除结果
  Future<bool> deleteLog(String filePath) async {
    try {
      final file = await localFile(filePath);
      if(!file.existsSync()) return true;
      await file.delete(recursive: false);
      return true;
    } catch(e) {
      rethrow;
    }
  }

  /// 清理日志文件夹
  Future<bool> clearLogs() async {
    try {
      if(_willClearLogs) return false;
      _willClearLogs = true;
      final logsDoc = await LogManager.instance.documentPath();
      await deleteDirectory(logsDoc, recursive: true);
      await filepath(filename());
      _willClearLogs = false;
      return true;
    } catch (e) {
      rethrow;
    }
  }

  /// 压缩日志文件夹
  Future<String> zipLogs() async {
    var encoder = ZipFileEncoder();
    final logsDoc = await LogManager.instance.documentPath();
    final dirPath = await LogManager.instance.temporaryPath();
    final zipPath = '$dirPath/zip_${filename()}.zip';
    encoder.zipDirectory(Directory(logsDoc), filename: zipPath);
    return zipPath;
  }
}
extension LogFile on LogManager {
  /// 创建一个指向[logFilePath]的引用
  Future<File> localFile(String logFilePath) async {
    final tempFile = File(logFilePath);
    if (tempFile.existsSync()) return tempFile;
    return await File(logFilePath).create(recursive: true);
  }
  /// 在[logFilePath]日志文件中，本地化存储[message]
  Future<File> localLog(String message, String logFilePath) async {
    final file = await localFile(logFilePath);
    final sink = file.openWrite(mode: FileMode.append);
    sink.write("\n$message");
    await sink.close();
    return file;
  }
  /// 获取logs文件列表
  Future<List<FileSystemEntity>> getLogs() async {
    String path = await documentPath();
    Stream<FileSystemEntity> fileList = Directory(path).list();
    List<FileSystemEntity> list = [];
    await for(FileSystemEntity fileSystemEntity in fileList){
      list.add(fileSystemEntity);
    }
    return list;
  }
}
extension LogFilePath on LogManager {
  /// 检查日志文件夹是否存在，如果不存在，则创建文件夹
  Future<void> checkDirectory(String root, String name) async {
    final file = Directory(root + "/" + name);
    try {
      if (await file.exists()) {
        return;
      }
      await file.create();
      return;
    } catch (e) {
      print("check directory error, error : ${e}");
    }
  }
  /// 删除绝对路径地址为[path]的文件夹，
  /// [recursive]: 是否递归删除，默认为false，如果未false，则删除的文件夹下如果存在文件，
  /// 则会删除失败
  Future<bool> deleteDirectory(String path, {bool recursive = false}) async {
    final file = Directory(path);
    final hasFile = await file.exists();
    if (!hasFile) return true;
    file.delete(recursive: recursive);
    return true;
  }
  /// 日志文件的文件夹绝对地址
  Future<String> documentPath() async {
    final rootPath = await directoryPath();
    await checkDirectory(rootPath, documentName);
    return "$rootPath/$documentName";
  }
  /// 日志文件的绝对地址
  Future<String> filepath(String filename) async {
    final docPath = await documentPath();
    return "$docPath/$filename.txt";
  }
  /// 找到正确的本地路径
  Future<String> directoryPath() async {
    final directory = await getApplicationDocumentsDirectory();
    return directory.path;
  }
  /// 临时文件夹的路径
  Future<String> temporaryPath() async {
    final dir = await getTemporaryDirectory();
    return dir.path;
  }

  /// 生成文件名称，目前的文件名称是以日期的天命名的
  String filename() {
    final datetime = DateTime.now();
    String yearStr = datetime.year.toString().padLeft(4, "0");
    String monthStr = datetime.month.toString().padLeft(2, "0");
    String dayStr = datetime.day.toString().padLeft(2, "0");
    return yearStr + '-' +monthStr + '-' + dayStr;
  }
}

extension CustomFileSystemEntity on FileSystemEntity {
  String get fillName {
    final tempPath = uri.path;
    List<String> list = tempPath.split('/');
    return list.last;
  }
  String get filename {
    final tempFillName = fillName;
    final List<String> list = tempFillName.split('.');
    return list.first;
  }
  String get fileType {
    final tempFillName = fillName;
    final List<String> list = tempFillName.split('.');
    return list.last;
  }
}

class FileEntity {
  final String path;

  FileEntity({
    required this.path,
  });

  @override
  String toString() {
    Map<String, String> params = {};
    params["path"] = path;
    return params.toString();
  }
}